

public class Expression {

    private static final int CONSTANT = 0;
    private static final int VARIABLE = 1;
    private static final int DOT_APPLICATION = 2;
    private static final int TILDE_APPLICATION = 3;
  
    private int type;
    private String var_name;
    private String const_value;
    private Expression[] subexpr;
  
    private Expression(int type, int number_of_subexpr) {
        this.type = type;
        subexpr = new Expression[number_of_subexpr];
    }
  
    public static Expression constant(String value) {
        Expression result = new Expression(CONSTANT, 0);
        result.const_value = value;
        return result;
    }
  
    public static Expression variable(String name) {
        Expression result = new Expression(VARIABLE, 0);
        result.var_name = name;
        return result;
    }
  
    public static Expression dotAppl(Expression sub1, Expression sub2) {
        Expression result = new Expression(DOT_APPLICATION, 2);
        result.subexpr[0] = sub1;
        result.subexpr[1] = sub2;
        return result;
    }
  
    public static Expression tildeAppl(Expression sub) {
        Expression result = new Expression(TILDE_APPLICATION, 1);
        result.subexpr[0] = sub;
        return result;
    }
    
    public Object eval() {
    	String result = evaluate(this); 

        return result;
    }
    
    private String evaluate(Expression e) {
    	String value = "";
    	int type = e.type;
    	
    	switch (type) {
    	case CONSTANT: 
    		value = e.const_value;
    		break;
    	case VARIABLE:
    		value = (String) Stack.getCellContentsOf(e.var_name);
    		break;
    	case DOT_APPLICATION:
    		String left = evaluate(e.subexpr[0]);
    		String right = evaluate(e.subexpr[1]);
    		value = left.substring(0, left.length()-1) + right.substring(1);
    		break;
    	case TILDE_APPLICATION:
    		value = evaluate(e.subexpr[0]).toUpperCase();
    		break;
    	}
    	
    	return value;
    	
    }
    
  public String toString(){
	  return this.var_name + " " + this.const_value + " " + this.type;
  }
}
